﻿#if false
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Util.IO
{
    public class ArrayPatch<T>
    {
        private ArrayPatchType type;
        private ArrayChunk<T>[] changes;

        /// <summary>
        /// Creates a patch by finding the changed elements between two
        /// arrays of the same type and length.
        /// </summary>
        /// <param name="current">A buffer of bytes to encode.</param>
        /// <param name="previous">Previous contents of the array.
        /// This array must have the same length as 'current'.</param>
        /// <returns>An array of non-overlapping DataChunks that cover the 
        /// changed portions of the buffer. This array may be empty if the
        /// two buffers are identical.
        /// </returns>
        public ArrayPatch(T[] previous, T[] current, int threshold, ArrayPatchType type)
        {
            if (current == null)
                throw new ArgumentNullException("current");
            if (previous == null)
            {
                this.type = type;
                this.changes = new ArrayChunk<T>[] {
                    new ArrayChunk<T>{
                        StartIndex = 0,
                        EndIndex = current.Length,
                        Data = GetArrayChunk(current, 0, current.Length)
                    }
                };
                return;
            }
            if (current.Length != previous.Length)
                throw new ArgumentException("Two arrays must have the same size.");

            // Let (i,j) be a locally maximal chunk of elements such that 
            // previous[i..j] = current[i..j] but extending either i or j by
            // one will cause them to be unequal. Suppose it takes 'threshold'
            // number of elements of overhead to encode a common chunk, then 
            // it makes sense to create a common chunk only if the common 
            // length n = (j - i + 1) > threshold.

            int length = current.Length;
            List<ArrayChunk<T>> diff = new List<ArrayChunk<T>>();
            int lastIndex = 0; // end-index of the last common block
            for (int index = 0; index < length; )
            {
                int n = GetCommonLength(previous, current, index);
                if (n > threshold) // makes sense to encode a common chunk
                {
                    if (index > lastIndex)
                    {
                        diff.Add(CreateChunk(previous, current, lastIndex, index, type));
                    }
                    lastIndex = index + n;
                }
                index += n;
                index += GetDistinctLength(previous, current, index);
            }

            // Encode the last distinct segment.
            if (lastIndex < length)
            {
                diff.Add(CreateChunk(previous, current, lastIndex, length, type));
            }

            // Create an ArrayPatch(Of T) object.
            this.type = type;
            this.changes = diff.ToArray();
        }

        public ArrayChunk<T>[] Changes { get { return changes; } }

        public void Apply(T[] array)
        {
            foreach (ArrayChunk<T> chunk in changes)
            {
                if (type == ArrayPatchType.Overwrite)
                    Array.Copy(chunk.Data, 0, array, chunk.StartIndex, chunk.Length);
                else
                    throw new NotSupportedException();
            }
        }

        private static ArrayChunk<T> CreateChunk(
            T[] previous, T[] current, int startIndex, int endIndex, ArrayPatchType type)
        {
            ArrayChunk<T> chunk = new ArrayChunk<T>
            {
                StartIndex = startIndex,
                EndIndex = endIndex,
            };

            switch (type)
            {
                case ArrayPatchType.Overwrite:
                    chunk.Data = GetArrayChunk(current, startIndex, endIndex);
                    break;
                default:
                    throw new NotSupportedException();
            }
            return chunk;
        }

        private static int GetCommonLength(T[] x, T[] y, int startIndex)
        {
            int i = startIndex;
            while (i < x.Length && EqualityComparer<T>.Default.Equals(x[i], y[i]))
                i++;
            return (i - startIndex);
        }

        private static int GetDistinctLength(T[] x, T[] y, int startIndex)
        {
            int i = startIndex;
            while (i < x.Length && !EqualityComparer<T>.Default.Equals(x[i], y[i]))
                i++;
            return (i - startIndex);
        }

        private static T[] GetArrayChunk(T[] array, int startIndex, int endIndex)
        {
            T[] chunk = new T[endIndex - startIndex];
            Array.Copy(array, startIndex, chunk, 0, chunk.Length);
            return chunk;
        }
    }

    public class ArrayChunk<T>
    {
        public int StartIndex { get; set; }
        public int EndIndex { get; set; }
        public T[] Data { get; set; }
        public int Length { get { return EndIndex - StartIndex; } }
    }

    /// <summary>
    /// Specifies whether a patch is incremental or overwriting.
    /// </summary>
    public enum ArrayPatchType
    {
        Overwrite = 0,
        Increment = 1,
    }
}
#endif
